//
//  CNIMageView.swift
//  Voice
//
//  Created by 卢逢卫 on 2024/3/12.
//

import UIKit

extension UIImage {

    public static func cn_generateGradientImageFrom(size: CGSize?, colors: [UIColor]) -> UIImage? {
        UIGraphicsBeginImageContextWithOptions(size ?? .zero, true, 0)
        defer { UIGraphicsEndImageContext() }
        
        guard let context = UIGraphicsGetCurrentContext() else { return nil }
        
        let colorSpace = CGColorSpaceCreateDeviceRGB()
        let cgColors = colors.map { $0.cgColor }
        guard let gradient = CGGradient(colorsSpace: colorSpace, colors: cgColors as CFArray, locations: nil) else {
            return nil
        }
        
        let startPoint = CGPoint.zero
        let endPoint = CGPoint(x: 0, y: size?.height ?? 0)
        context.drawLinearGradient(gradient, start: startPoint, end: endPoint, options: [])
        
        return UIGraphicsGetImageFromCurrentImageContext()
    }

    public static func cn_generateImageFrom(color: UIColor) -> UIImage {
        let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
        UIGraphicsBeginImageContext(rect.size)
        defer { UIGraphicsEndImageContext() }
        
        guard let context = UIGraphicsGetCurrentContext() else { return UIImage() }
        
        context.setFillColor(color.cgColor)
        context.fill(rect)
        
        return UIGraphicsGetImageFromCurrentImageContext() ?? UIImage()
    }

    public static func cn_changeImageColorForImage(oldImage: UIImage, newColor: UIColor, blendMode: CGBlendMode = .destinationIn, alpha: CGFloat = 1.0) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(oldImage.size, false, oldImage.scale)
        defer { UIGraphicsEndImageContext() }
        
        guard let context = UIGraphicsGetCurrentContext(), let cgImage = oldImage.cgImage else {
            return oldImage
        }
        
        let rect = CGRect(x: 0, y: 0, width: oldImage.size.width, height: oldImage.size.height)
        context.scaleBy(x: 1, y: -1)
        context.translateBy(x: 0, y: -rect.size.height)
        context.setBlendMode(blendMode)
        context.setAlpha(alpha)
        context.draw(cgImage, in: rect)
        
        context.clip(to: rect, mask: cgImage)
        context.setFillColor(newColor.cgColor)
        context.fill(rect)
        
        return UIGraphicsGetImageFromCurrentImageContext() ?? oldImage
    }

    public static func cn_changeImageSizeForImage(oldImage: UIImage, size: CGSize?) -> UIImage {
        let newSize = size ?? oldImage.size
        UIGraphicsBeginImageContextWithOptions(newSize, false, oldImage.scale)
        defer { UIGraphicsEndImageContext() }
        
        oldImage.draw(in: CGRect(origin: .zero, size: newSize))
        return UIGraphicsGetImageFromCurrentImageContext() ?? oldImage
    }

    public static func cn_compressImageForData(oldImage: UIImage, maxLengh: CGFloat, maxKB: CGFloat) -> Data? {
        var compression: CGFloat = 1.0
        var maxCompression: CGFloat = 0.1
        
        guard let imageData = oldImage.jpegData(compressionQuality: compression), imageData.count > Int(maxLengh) else {
            return oldImage.jpegData(compressionQuality: 1.0)
        }
        
        while compression > maxCompression && imageData.count > Int(maxLengh) {
            compression -= 0.1
            guard let newImageData = oldImage.jpegData(compressionQuality: compression) else {
                return nil
            }
            
            if newImageData.count < Int(maxLengh) * Int(maxKB) {
                return newImageData
            }
        }
        
        return nil
    }

    public static func cn_generateImageFrom(backgroundImage: UIImage, images: [UIImage], sizes: [CGSize], origins: [CGPoint]) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(backgroundImage.size, false, backgroundImage.scale)
        defer { UIGraphicsEndImageContext() }
        
        backgroundImage.draw(in: CGRect(origin: .zero, size: backgroundImage.size))
        
        for (index, image) in images.enumerated() {
            let size = sizes[index]
            let origin = origins[index]
            image.draw(in: CGRect(origin: origin, size: size))
        }
        
        return UIGraphicsGetImageFromCurrentImageContext() ?? backgroundImage
    }
    
    public func cn_drawTextInImage(text: [NSAttributedString], origins: [CGPoint]) -> UIImage {
        UIGraphicsBeginImageContextWithOptions(size, false, scale)
        defer { UIGraphicsEndImageContext() }
        
        draw(at: .zero)
        
        for (index, attributedText) in text.enumerated() {
            let origin = origins[index]
            attributedText.draw(at: origin)
        }
        
        return UIGraphicsGetImageFromCurrentImageContext() ?? self
    }
}
